(function() {

    // Class Carrot
    var Carrot = function(img, x, y, w, h) {
        this.image = img;
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
        this.existTime = 0;
        this.createTime = new Date();
    }

    Carrot.prototype.draw = function(context) {
        this.existTime = new Date - this.createTime;
        context.drawImage(this.image, this.x - 60, this.y - 30, this.w, this.h);   
    }

    Carrot.prototype.update = function() {
        this.existTime = new Date - this.createTime;
        return this.existTime < 500;
    }


    // Class Clock
    var Clock = function(img, x, y, w, h) {
        this.image = img;
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
    }

    Clock.prototype.draw = function(context, num) {
        context.save();
        context.drawImage(this.image, this.x, this.y, this.w, this.h);
        context.font = '40px Microsoft YaHei';
        context.fillStyle = 'rgb(115, 75, 40)';
        context.textAlign = "right";
        context.textBaseline = "middle";
        context.fillText((num + 100).toString().substr(1) + "'", this.x + 150, this.y + 70);
        context.restore();
    }


    // Class Hole
    var Hole = function(img) {
        this.img = img;
    }

    Hole.prototype.draw = function(context, frameX, frameY, x, y, w, h) {
        context.drawImage(this.img, frameX, frameY, w, h, x, y, w, h);
    }


    // Class Mole
    var Mole = function(x, y, w, h, frameX, frameY, frameW, weight, speed, score, duration) {
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = 0;
        this.finalH = h;
        this.finalY = y - h;
        this.frameX = frameX;
        this.frameY = frameY;
        this.frameW = frameW;
        this.speed = speed + 2 * Math.random();
        this.duration = duration;
        this.hideDuration = this.duration;
        this.state = 'hide';
        this.up = true;
        this.score = score || 0;
        this.weight = weight;
    }

    Mole.prototype.draw = function(context, img) {
        context.drawImage(img, this.frameX, this.frameY, this.frameW, this.h, this.x, this.y, this.w, this.h);   
    }

    Mole.prototype.update = function(moleMatrix, i, j) {
        if (this.state === 'show') {
            if (this.up) {
                this.y -= this.speed;
                this.h += this.speed;
                if (this.h >= this.finalH) {
                    this.h = this.finalH;
                    this.y = this.finalY; 
                    this.up = false;
                }
            } else {
                this.y += this.speed;
                this.h -= this.speed;
                if (this.h <= 0) {
                    this.reset(moleMatrix, i, j);
                }
            }
        } else if (this.state === 'feed') {
            this.frameX = this.frameW;
            if ((this.hideDuration--) <= 0) {
                this.reset(moleMatrix, i, j);
            }
        }
    }

    Mole.prototype.reset = function(moleMatrix, i, j) {
        this.y = this.y + this.h;
        this.h = 0;
        this.up = true;
        this.state = 'hide';
        this.frameX = 0;
        this.hideDuration = this.duration;
        moleMatrix[i][j] = 0;
    }


    // Class Process
    var Process = function(img, thumb, x, y, w, h, barW, barH, total) {
        this.img = img;
        this.thumb = thumb;
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
        this.barW = barW;
        this.barH = barH;
        this.process = 0;
        this.total = total;
    }

    Process.prototype.draw = function(context, num) {
        num = (num < 0 ? 0 : num);
        context.save();
        context.drawImage(this.img, this.x, this.y, this.w, this.h);
        context.beginPath();
        context.moveTo(this.x + 52, this.y + 58);
        context.lineTo(this.x + 52 + this.process, this.y + 58);
        context.strokeStyle = 'rgb(155, 231, 66)'; 
        context.lineWidth = this.barH;
        context.stroke();
        context.drawImage(this.thumb, this.x + 19, this.y + 26, this.barH, this.barH);
        context.font = '48px Microsoft YaHei';
        context.fillStyle = 'rgb(115, 75, 40)';
        context.textAlign = "center";
        context.textBaseline = "middle";
        context.fillText((num + 10000).toString().substr(1), this.x + 200, this.y + 56);
        context.restore();
    }

    Process.prototype.update = function(num) {
        if (num >= this.total) {
            this.process = this.barW;
        } else if (num <= 0) {
            this.process = 0;
        } else {
            this.process = (num / this.total * this.barW);
        }
    }


    // Class Scene
    var Scene = function(img) {
        this.image = img;
    }

    Scene.prototype.draw = function(context, w, h) {
        context.drawImage(this.image, 0, 0, w, h);   
    }


    // Class Score
    var Score = function(w, h, frameW, frameH, duration) {
        this.show = false;
        this.duration = duration;
        this.w = w;
        this.h = h;
        this.frameW = frameW;
        this.frameH = frameH;
        this.frameX = 0;
        this.hideDuration = this.duration;
        this.speed = 2;
        this.x;
        this.y;
    }

    Score.prototype.draw = function(context, img) {
        if (this.show) {
            context.save();
            context.globalAlpha = this.hideDuration / this.duration;
            context.drawImage(img, this.frameX, 0, this.frameW, this.frameH, this.x, this.y, this.w, this.h);
            context.restore();
        }
    }

    Score.prototype.locate = function(x, y, score) {
        this.x = x;
        this.y = y;
        this.show = true;
        if (score == 1) {
            this.frameX = 0
        } else {
            this.frameX = this.frameW;
        }
    }

    Score.prototype.update = function() {
        if (this.show) {
            this.y -= this.speed;
            if ((this.hideDuration--) <= 0) {
                this.show = false;
                this.hideDuration = this.duration;
            }
        }
    }
    Score.prototype.reset = function() {
        this.show = false;
    }


    // Class Star
    var Star = function(w, h, frameW, frameH, duration) {
        this.show = false;
        this.w = w;
        this.h = h;
        this.frameW = frameW;
        this.frameH = frameH;
        this.frameX = 0;
        this.duration = duration;
        this.hideDuration = this.duration;
        this.x;
        this.y;
    }

    Star.prototype.draw = function(context, img) {
        if (this.show) {
            context.drawImage(img, this.frameX, 0, this.frameW, this.frameH, this.x, this.y, this.w, this.h);
        }
    }

    Star.prototype.locate = function(x, y) {
        this.x = x;
        this.y = y;
        this.show = true;
    }

    Star.prototype.update = function() {
        if (this.show) {
            this.frameX = (this.frameX == 0 ? this.frameW : 0);
            if ((this.hideDuration--) <= 0) {
                this.show = false;
                this.hideDuration = this.duration;
            }
        }
    }
    Star.prototype.reset = function() {
        this.show = false;
    }

    var MoleAttack = function(id, w, h, images, stuff, frames, sounds) {

        this.canvas = document.getElementById(id);
        this.context = this.canvas.getContext('2d');
        this.canvas.width = w;
        this.canvas.height = h;

        this.stuff = stuff;
        this.frames = frames;

        this.readyInterval;
        this.molesUpdateInterval;

        this.animation;

        this.matrixLastUpdateTime = 0;
        this.matrixUpdateInterval = 1000;

        this.carrots = [];
        this.scene;

        this.score;

        this.moleMatrix = [
            [0, 0, 0],
            [0, 0, 0],
            [0, 0, 0]
        ];

        this.moles = [];
        this.stars = [];
        this.scores = [];
        this.callbacks = [];

        this.scorePass = 20;
        this.timeLimit = 30;
        this.countDown;

        this.audioInstance = {};

        this.imageManager;
        // this.audioManager;

        this.isIos = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);

        this.load(images, sounds);
    }

    MoleAttack.prototype.load = function(images, sounds) {
        var self = this;
        self.drawLoading(self);
        self.imageManager = new ImageManager();
        // self.audioManager = new AudioManager();
        self.imageManager.load(images);
        self.imageManager.onReady(function() {
            self.init();
            // if (self.isIos) {
            //     // self.audioManager.ready(function() {
            //         self.init();
            //     });
            // } else {
            //     self.init();
            // }
            // self.audioManager.load(sounds);
        });
    }

    MoleAttack.prototype.drawLoading = function(self) {
        self.context.save();
        self.context.font = "48px Microsoft YaHei";
        self.context.fillStyle = "#000000";
        self.context.fillRect(0, 0, self.canvas.width, self.canvas.height);
        self.context.fillStyle = "#FFFFFF";
        self.context.textAlign = "center";
        self.context.textBaseline = "middle";
        self.context.fillText('loading...', self.canvas.width / 2, self.canvas.height / 3);
        self.context.restore()
    }

    MoleAttack.prototype.init = function() {
        var self = this;
        // if (self.isIos) {
        //     self.canvas.addEventListener('touchstart', loadAudio);
        // };
        self._createMoles(self);
        self._createProcess(self);
        self._createClock(self);
        self._createScene(self.imageManager.get('bg_game'));
        self._createHole(self.imageManager.get('bg_hole'));
        self.start();
        // function loadAudio() {
            // self.audioManager.reload('background');
            // self.audioManager.reload('pass');
            // self.audioManager.reload('unpass');
            // self.canvas.removeEventListener('touchstart', loadAudio);
        // }
    }

    MoleAttack.prototype._createMoles = function(self) {
        for (var i=0; i < 3; i++) {
            var rowMoles = [];
            var rowStars = [];
            var rowScores = [];
            var frame = self.frames.mole;
            for (var j=0; j < 3; j++) {
                var posMole = self.stuff.mole[i][j];
                var colMoles = [
                    new Mole(posMole.x, posMole.y, posMole.w, posMole.h, frame[0][0].x, frame[0][0].y, frame[0][0].w, 0.6, 6, 1, 30),
                    new Mole(posMole.x, posMole.y, posMole.w, posMole.h, frame[1][0].x, frame[1][0].y, frame[0][0].w, 0.2, 6, -1, 30),
                    new Mole(posMole.x, posMole.y, posMole.w, posMole.h, frame[2][0].x, frame[2][0].y, frame[0][0].w, 0.2, 6, -1, 30)
                ];
                var star = new Star(self.stuff.star.w, self.stuff.star.h, self.frames.star.w, self.frames.star.h, 9);
                var score = new Score(self.stuff.score.w, self.stuff.score.h, self.frames.score.w, self.frames.score.h, 30);
                rowMoles.push(colMoles);
                rowStars.push(star);
                rowScores.push(score);
            }
            self.moles.push(rowMoles);
            self.stars.push(rowStars);
            self.scores.push(rowScores);
        }
    }

    MoleAttack.prototype._createProcess = function(self) {
        this.process = new Process(self.imageManager.get('process'), self.imageManager.get('thumb'), self.stuff.process.x, self.stuff.process.y, self.stuff.process.w, self.stuff.process.h, self.stuff.process.barW, self.stuff.process.barH, self.scorePass);
    }

    MoleAttack.prototype._createClock = function(self) {
        this.clock = new Clock(self.imageManager.get('clock'), self.stuff.clock.x, self.stuff.clock.y, self.stuff.clock.w, self.stuff.clock.h);
    }

    MoleAttack.prototype._createScene = function(img) {
        this.scene = new Scene(img);
    }

    MoleAttack.prototype._createHole = function(img) {
        this.hole = new Hole(img);
    }

    MoleAttack.prototype.start = function() {
        var index = 3,
            self = this;
        // if (self.isIos) {
            // self.audioManager.play('countdown');
        // }
        self.ready(self, index--);
        self.readyInterval = setInterval(function() {
            self.ready(self, index--);
        }, 1000);
        self.reset(self);
    }

    MoleAttack.prototype.reset = function(self) {
        self.countDown = self.timeLimit;
        self.score = 0;
        for (var i=0; i < 3; i++) {
            for (var j=0; j < 3; j++) {
                for (var k=0; k < 3; k++) {
                    self.moles[i][j][k].reset(self.moleMatrix, i, j);
                }
                self.scores[i][j].reset();
                self.stars[i][j].reset();
            }
        }
        self.process.update(self.score);
    }

    MoleAttack.prototype.ready = function(self, index) {
        if (index <= 0 ) {
            clearInterval(self.readyInterval);
            self.play(self);
        } else {
            self.drawReadyScene(self, index);
        }
    }

    MoleAttack.prototype.play = function(self) {
        // if (self.isIos) {
        //     self.canvas.addEventListener('touchstart', playAudio);
        //     // self.audioManager.play('background', {loop: 'loop'});
        // }
        // function playAudio() {
        //     // self.audioManager.play('background');
        //     self.canvas.removeEventListener('touchstart', playAudio);
        // }
        self.addListener(self);
        self.molesUpdateInterval = setInterval(function() {
            self.updateMoles(self);
        }, 30);
        self.starsUpdateInterval = setInterval(function() {
            self.updateStars(self);
        }, 100);
        self.countDownInterval = setInterval(function() {
            self.updateClock(self);
        }, 1000);
        function animate(time) {
            self.randomMoleMatrix(self);
            self.drawScene(self);
            self.drawMoles(self);
            self.drawScores(self);
            self.drawCarrots(self);
            self.drawProcess(self);
            self.drawClock(self);
            self.animation = requestAnimationFrame(animate);            
        }
        self.animation = requestAnimationFrame(animate);
        // self.audioInstance.background = self.audioManager.play('background', {loop: 'loop'});
    }

    MoleAttack.prototype.drawScene = function(self) {
        self.context.clearRect(0, 0, self.canvas.width, self.canvas.height);   
        self.scene.draw(self.context, self.canvas.width, self.canvas.height);   
    }

    MoleAttack.prototype.drawProcess = function(self) {
        self.process.draw(self.context, self.score);   
    }

    MoleAttack.prototype.drawClock = function(self) {
        self.clock.draw(self.context, self.countDown);   
    }

    MoleAttack.prototype.drawCarrots = function(self) {
        for (var i=0; i < self.carrots.length; i++) {
            if (self.carrots[i].update()) {
                self.carrots[i].draw(self.context);
            } else {
                self.carrots.shift();
                i--;
            }
        }
    }

    MoleAttack.prototype.drawReadyScene = function(self, index) {
        self.drawScene(self);
        self.context.save();
        self.context.fillStyle = 'rgba(60, 60, 60, 0.5)';
        self.context.fillRect(0, 0, self.canvas.width, self.canvas.height);
        self.context.drawImage(self.imageManager.get('ready_' + index), this.stuff.ready.x, this.stuff.ready.x, this.stuff.ready.w, this.stuff.ready.h);   
        self.context.restore();
    }

    MoleAttack.prototype.addListener = function(self) {
        // self.canvas.addEventListener('touchstart', function(e) {
        self.canvas.ontouchstart = function(e) {
            for (var i=0, l=e.changedTouches.length; i < l; i++) {
                var coordinate = windowToCanvas(self.canvas, e.changedTouches[i].clientX, e.changedTouches[i].clientY);
                var carrot = new Carrot(self.imageManager.get('carrot'), coordinate.x, coordinate.y, self.stuff.carrot.w, self.stuff.carrot.h);
                self.carrots.push(carrot);
                self.collisionDetect(self, coordinate.x, coordinate.y);
            }
        }
        // });
    }

    MoleAttack.prototype.randomMoleMatrix = function(self){
        var now = new Date();
        if ((now - self.matrixLastUpdateTime) > self.matrixUpdateInterval) {
            self.matrixLastUpdateTime = now;
            var n = randomInt(1, 3);
            for (var i=1; i <= n; i++) {
                var a = randomInt(0, 2);
                var b = randomInt(0, 2);
                if(self.moleMatrix[a][b] == 1){  // 存在地鼠，不产生地鼠
                    i--;
                } else {
                    self.moleMatrix[a][b] = 1;    //设置已存在地鼠
                    // var k = randomInt(0, 2);
                    // self.moles[a][b][k].state = 'show';
                    var m = Math.random();
                    var start = 0;
                    var end = 0;
                    for (var k=0; k < 3; k++) {
                        end += self.moles[a][b][k].weight;
                        if (m >= start && m < end) {
                            self.moles[a][b][k].state = 'show';
                            break;
                        }
                    }
                }
            }
        }
        // console.log(self.moleMatrix);
        // console.log(self.moles);
    }

    MoleAttack.prototype.updateMoles = function(self) {
        for (var i=0; i < 3; i++) {
            for (var j=0; j < 3; j++) {
                self.scores[i][j].update();
                for (var k=0; k < 3; k++) {
                    self.moles[i][j][k].update(self.moleMatrix, i, j);
                }
            }
        }
    }

    MoleAttack.prototype.updateStars = function(self) {
        for (var i=0; i < 3; i++) {
            for (var j=0; j < 3; j++) {
                self.stars[i][j].update();
            }
        }
    }

    MoleAttack.prototype.updateClock = function(self) {
        if ((--this.countDown) <= 0) {
            setTimeout(function() {
                self.gameover(self);
            }, 50)
        };
    }

    MoleAttack.prototype.gameover = function(self) {
        cancelAnimationFrame(self.animation);
        clearInterval(self.molesUpdateInterval);
        clearInterval(self.starsUpdateInterval);
        clearInterval(self.countDownInterval);
        self.callbacks.forEach(function(f) {
            f(self.score);
        });
        setTimeout(function() {
            if (self.isIos) {
                // self.audioManager.stop('background');
                self.score >= self.scorePass ? self.audioManager.play('pass') : self.audioManager.play('unpass');
            }          
        }, 250);
    }

    MoleAttack.prototype.onGameover = function() {
        for (var i=0, l=arguments.length; i < l; i++) {
            this.callbacks.push(arguments[i]);
        }
    }

    MoleAttack.prototype.drawMoles = function(self) {
        for (var i=0; i < 3; i++) {
            for (var j=0; j < 3; j++) {
                for (var k=0; k < 3; k++) {
                    self.moles[i][j][k].draw(self.context, self.imageManager.get('moles'));
                }
                self.stars[i][j].draw(self.context, self.imageManager.get('star'));
            }
            self.hole.draw(self.context, self.frames.hole[i].x, self.frames.hole[i].y, self.stuff.hole[i].x, self.stuff.hole[i].y, self.frames.hole[i].w, self.frames.hole[i].h);
        }
    }

    MoleAttack.prototype.drawScores = function(self) {
        for (var i=0; i < 3; i++) {
            for (var j=0; j < 3; j++) {
                self.scores[i][j].draw(self.context, self.imageManager.get('score'));
            }
        }
    }

    MoleAttack.prototype.collisionDetect = function(self, x, y) {
        loop:
        for (var i=0; i < 3; i++) {
            for (var j=0; j < 3; j++) {
                var star = self.stars[i][j];
                var score = self.scores[i][j];
                for (var k=0; k < 3; k++) {
                    var mole = self.moles[i][j][k];
                    if ((x > mole.x) && (x < mole.x + mole.w) && (y > mole.y) && (y < mole.y + mole.h)) {
                        if (mole.state != 'feed') {
                            mole.state = 'feed';
                            if ((self.score += mole.score) < 0) {
                                self.score = 0;
                            };
                            // if (!this.isIos) {
                                // self.audioManager.stop('background');                                
                            // }
                            if (mole.score < 0) {
                                star.locate(mole.x + 10, mole.y - 20);
                                // if (self.isIos) {
                                    // self.audioManager.play('wrong');
                                // }
                            // } else {
                                // if (self.isIos) {
                                    // self.audioManager.play('correct');
                                // };
                            }
                            // if (!this.isIos) {
                            //     sound.on('complete', function() {
                                    // self.audioInstance.background.paused = false;
                            //     });
                            // }
                            score.locate(mole.x + 100, mole.y + 10, mole.score);
                            self.process.update(self.score);
                        }
                        break loop;
                    }
                }
            }
        }
    }

    window.Carrot = Carrot;
    window.Clock = Clock;
    window.Hole = Hole;
    window.Mole = Mole;
    window.Process = Process;
    window.Scene = Scene;
    window.Score = Score;
    window.Star = Star;
    window.MoleAttack = MoleAttack;

})();